package com.ruoyi.wss;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.codec.digest.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.TreeMap;

public class DahuaSignatureUtil {

    private static final String SCHEME = "LC-HMAC-SHA256";
    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");

    /**
     * 生成HTTP请求签名
     */
    public static String generateHttpSignature(String method, String contentMd5,
                                               String contentType, String xLcDate,
                                               Map<String, String> headers,
                                               String canonicalizedResource,
                                               String accessSecret) {
        try {
            String stringToSign = buildStringToSign(method, contentMd5, contentType,
                    xLcDate, headers, canonicalizedResource);
            return calculateSignature(stringToSign, accessSecret);
        } catch (Exception e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }

    /**
     * 生成WSS连接签名
     */
    public static String generateWssSignature(String accessKeyId, String accessSecret) {
        try {
            String xLcDate = getCurrentUtcTime();
            String stringToSign = "GET\n\n\n" + xLcDate + "\n\n/";
            String signature = calculateSignature(stringToSign, accessSecret);
            return SCHEME + " " + accessKeyId + ":" + signature;
        } catch (Exception e) {
            throw new RuntimeException("生成WSS签名失败", e);
        }
    }

    /**
     * 构建待签名字符串
     */
    private static String buildStringToSign(String method, String contentMd5,
                                            String contentType, String xLcDate,
                                            Map<String, String> headers,
                                            String canonicalizedResource) {

        StringBuilder stringToSign = new StringBuilder();
        stringToSign.append(method).append("\n");
        stringToSign.append(contentMd5 != null ? contentMd5 : "").append("\n");
        stringToSign.append(contentType != null ? contentType : "").append("\n");
        stringToSign.append(xLcDate).append("\n");

        // 添加CanonicalizedDHHeaders
        String canonicalizedHeaders = buildCanonicalizedHeaders(headers);
        stringToSign.append(canonicalizedHeaders);

        // 添加CanonicalizedResource
        stringToSign.append(canonicalizedResource);

        return stringToSign.toString();
    }

    /**
     * 构建规范化头部
     */
    private static String buildCanonicalizedHeaders(Map<String, String> headers) {
        if (headers == null || headers.isEmpty()) {
            return "";
        }

        // 过滤出X-LC-开头的头部并按字典序排序
        TreeMap<String, String> lcHeaders = new TreeMap<>();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            String key = entry.getKey().toLowerCase();
            if (key.startsWith("x-lc-")) {
                lcHeaders.put(key, entry.getValue().trim());
            }
        }

        StringBuilder canonicalized = new StringBuilder();
        for (Map.Entry<String, String> entry : lcHeaders.entrySet()) {
            canonicalized.append(entry.getKey())
                    .append(":")
                    .append(entry.getValue())
                    .append("\n");
        }

        return canonicalized.toString();
    }

    /**
     * 计算签名
     */
    private static String calculateSignature(String stringToSign, String accessSecret) {
        try {
            byte[] signatureBytes = HmacUtils.hmacSha256(
                    accessSecret.getBytes(StandardCharsets.UTF_8),
                    stringToSign.getBytes(StandardCharsets.UTF_8)
            );
            return Base64.encodeBase64String(signatureBytes);
        } catch (Exception e) {
            throw new RuntimeException("计算签名失败", e);
        }
    }

    /**
     * 计算Content-MD5
     */
    public static String calculateContentMd5(String content) {
        if (content == null || content.isEmpty()) {
            return "";
        }
        byte[] md5Bytes = DigestUtils.md5(content);
        return Base64.encodeBase64String(md5Bytes);
    }

    /**
     * 获取当前UTC时间
     */
    public static String getCurrentUtcTime() {
        return ZonedDateTime.now(ZoneOffset.UTC).format(DATE_FORMATTER);
    }
}
